//! This is a simple example of 
//! 1. create_signal + 闭包
//! 2. create_resource + async fn
//! 3. #[server("SendNortify","/api")]
//! 4. create_action + async fn.
//! 5. Await 组件
//! 
use leptos::*;
use serde::*;
use chrono::prelude::*;
use leptos_meta::Title;
// use leptos::{html::Input, *};
use thiserror::Error;
use anyhow::Result;
use reqwest::header::HeaderMap;
use std::collections::HashMap;
use common::{SubFutureInfo, Config};
use crate::*;
use leptos::LeptosOptions;

#[component]
pub fn YeePage() -> impl IntoView {
    
    let (code_name, set_code_name) = create_signal(String::from("AP"));
    let dict: HashMap<String, Vec<SubFutureInfo>> = HashMap::new();
    let (codes_dict, set_codes_dict) = create_signal(dict);      
    let async_dict = create_resource(
        // move || code_name.get(),  // 这里没有使用code_name，而是直接传一个字符串, 
        // 因为只希望在初始化时运行一次，结果将被缓存在codes_dict中。
        move || "AP",        
        |value|          
          async move {                                 
            let cfg = get_config().await.unwrap();        
            let dict = cfg.futures.clone(); 
            dict
          },
    );       
    
    let state = use_context::< LeptosOptions >();    
    logging::log!("in component, extract_state_from axum {:?}", state);      
    
    view! {
      <div align="center">
        <table border="0" cellpadding="0" cellspacing="0" id="futures" width="800px" >
          <tr><td>
            <FuturesSelect on:change=move |ev| {
              let v = event_target_value(&ev);
              // get from dict
                leptos::logging::log!("select code: {:?}", v);
                set_code_name.set(v);                
            }/>            
          </td></tr>
        </table>
      </div>
      <div align="center">      
      <Transition fallback=move || view! { <div>loading...</div> }  >
        {
          move || {              
              let code = code_name.get();      
              let dict =  codes_dict.get(); 
              if dict.len() == 0 {             
                    logging::log!("dict empty, try to get data from server");
                    if let Some(dict) = async_dict.get(){ 
                        logging::log!("yes , get data from server and set to codes_dict! len =  {:?}", dict.len());
                        if dict.len() > 0 {
                            set_codes_dict.set(dict);
                        }                        
                    }             
              }
              let dict =  codes_dict.get();    
              let items:Vec<SubFutureInfo> = if dict.contains_key(&code) {
                  dict.get(&code).unwrap().clone()
                }else{
                  vec![]
                };
                if items.len() == 0 {
                  logging::log!("no data, why?  ");
                }                
                view!{
                {
                items.into_iter().map(|item| {
                  let link1 = format!("http://{}/yee/static/out/{}.png", item.addr, item.code);
                  let link2 = format!("http://{}/yee/static/out/{}-Dog.png", item.addr, item.code);
                  let link3 = format!("http://{}/yee/static/out/{}-VI.png", item.addr, item.code);
                  let link4 = format!("http://{}/yee/static/out/{}-Simple.png", item.addr, item.code);
                  let name = format!("{}", item.code);
                  view! { {name} : {link1.clone()} <br/>
                      <p> <img src={link1} width="100%" />  </p> 
                      <p> <img src={link2}  width="100%" />  </p> 
                      <p> <img src={link3}  width="100%" />  </p> 
                      <p> <img src={link4}  width="100%"/>  </p> 
                  }
                }
                  ).collect_view() }
                }                                           
              
          }
        }     
        </Transition>  
      </div>
    }
}

#[component]
fn FuturesSelect() -> impl IntoView {
    view! {
      <select style="width: 100px; font-size: 18px;">
        <option value="AP">"苹果:AP"</option>
        <option value="rb">"螺纹钢:rb"</option>
        <option value="hc">"热卷:hc"</option>
        <option value="MA">"甲醇:MA"</option>
        <option value="SR">"白糖:SR"</option>
        <option value="SA">"纯碱:SA"</option>
      </select>
    }
}

#[server]
pub async fn get_config() -> Result< Config, ServerFnError> {
    use http::request::Parts;
    // this is just an example of how to access server context injected in the handlers
    let req_parts = use_context::<Parts>();
    let server_addr = if let Some(req_parts) = req_parts {
        req_parts.headers.get("host").unwrap().to_str().unwrap().to_string()
    }else{
        return Err(ServerFnError::ServerError("can't get server_addr from server fn by Parts".to_string()));      
    };
    logging::log!("in server_fn, get host_addr = {}", server_addr);
 
    let state = use_context::< LeptosOptions >();
    logging::log!("in server_fn, extract_state_from axum {:?}", state);      
 
    if let Ok(cfg) = proxy_axum_config(&server_addr).await{
        return Ok(cfg);   
    }else{
        return Err(ServerFnError::ServerError("No config found".to_string()));
    }
}

pub async fn proxy_axum_config(server_addr:&str) -> Result< Config > {        
    
    logging::log!("get_config") ;   
    let api = format!("http://{}/loong/api/get_config", server_addr);
    logging::log!("api = {:#?}", api);
    
    let client = reqwest::Client::new();
    let headers = HeaderMap::new();
    //headers.insert("Authorization", "Bearer xman".parse()?);
    // headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);
    let r:Config = client    
        .get(&api)
        .headers(headers)
        .send()
        .await?
        .json()
        .await?;           
    return std::result::Result::Ok(r);
}

